# note: printf is used instead of echo to avoid backslash
# processing and to properly handle values that begin with a '-'.

# appends a command to a trap
#
# - 1st arg:  code to add
# - remaining args:  names of traps to modify
#
trap_add() {
    new_cmd=$1
    shift
    for trap_name in "$@"; do
        trap -- "$(
            # print the new trap command
            printf '%s\n' "${new_cmd}"
            # helper fn to get existing trap command from output
            # of trap -p
            extract_trap_cmd() { printf '%s\n' "$3"; }
            # print existing trap command with newline
            eval "extract_trap_cmd $(trap -p "${trap_name}")"
        )" "${trap_name}"
    done
}
# set the trace attribute for the above function.  this is
# required to modify DEBUG or RETURN traps because functions don't
# inherit them unless the trace attribute is set
declare -f -t trap_add